const { ccclass, property } = cc._decorator;
import PlayHero from '../Game/PlayHero';
import HeroCollider from './HeroCollider';
import placeWayControl from '../World/placeWayControl';
import SkillsNodeControl from '../SkillBuild/SkillsNodeControl';
import WayBaseControl from '../World/WayBaseControl';
import MyEnums from '../MyEnums';
import Skill from '../SkillBuild/Skill';
import HeroTarget from "../SkillBuild/HeroTarget";
import SkillLaunch from '../SkillBuild/SkillLaunch';
import TargetBase from '../SkillAttack/TargetBase';

@ccclass
export default class HeroControl extends cc.Component {

    @property
    get isJumping() {
        return this._jumpState > 0;
    }
    @property
    get jumpState() {
        return this._jumpState;
    }

    @property(cc.Node)
    HStatusPool: cc.Node = null;
    @property(cc.Node)
    HRefreshPool: cc.Node = null;

    @property(cc.Node)
    skillStore: cc.Node = null;

    @property(cc.Node)
    skillContrl: cc.Node = null;

    @property(cc.Node)
    uiNode: cc.Node = null;

    @property(cc.Node)
    ObjectNode: cc.Node = null;

    @property(cc.Node)
    _lifeBarNode: cc.Node = null;

    @property(cc.Node)
    _followNode: cc.Node = null;

    @property({
        type: [cc.Component.EventHandler],
        tooltip: "技能释放后的回调"
    })
    SkillBackEvents: Array<cc.Component.EventHandler> = [];
    @property({
        type: [cc.Component.EventHandler],
        tooltip: "hero死亡"
    })
    DieEvents: Array<cc.Component.EventHandler> = [];

    private heroBody: cc.Node = null;
    private _isjumping: number = 2;
    private _jumpState: number = 0;//0未起跳，1跳起，-1起跳下落
    private _animations: cc.Animation = null;
    private _heroMamaget: HeroManager = null;
    private _faceTo: number = 1;
    private _rigidBody: cc.RigidBody = null;
    private _runState: boolean = false;
    private _uiNodeControl: PlayHero = null;
    private _HeroHelper: HeroHelper = null;
    private isSpeedUp: boolean;
    private _placeWay: cc.Node = null;
    private onSkillNode: cc.Node = null;//当前已选中的施放技能
    private onSkillId: cc.Node = null;//当前已选中的施放技能ID
    private onSkillCount: number = 0;//当前已选中的技能可施放次数
    private PutNode: cc.Node = null;//当前已选中的放置技能
    private _SkillsNodeControl: SkillsNodeControl = null;//技能施法面板控制器
    private isSetWaying: boolean = false;
    private _SkillsNode: cc.Node = null;
    private _speedUpNode: cc.Node = null;
    private _progress: cc.ProgressBar = null;
    private _defaultSkillLaunch: SkillLaunch = null;
    private updateTime: number = 0.3;

    onLoad() {
        this.heroBody = this.node.children[0].getChildByName("body");
        this._followNode = this.node.children[0].getChildByName("follow");
        this._lifeBarNode = this._followNode.getChildByName("life");
        this._heroMamaget = HeroManager.getInstance();
        this._HeroHelper = HeroHelper.getInstance();
        this._uiNodeControl = this.uiNode.getComponent(PlayHero);
        this._animations = this.heroBody.getComponent(cc.Animation);
        this._rigidBody = this.heroBody.getComponent(cc.RigidBody);
        this._progress = this._lifeBarNode.getComponent(cc.ProgressBar);
        this._placeWay = this.skillStore.getChildByName("placeWay");
        this.node.on('footBeginContact', this.BeginContact, this);
        this.node.on('footContactChange', this.ChangeInContact, this);
        this.node.on('footEndContact', this.EndContact, this);
        this._animations.on('lastframe', this.onLastFrame, this);
        this._speedUpNode = this.skillStore.getChildByName('speedUp');
        this.schedule(this.updateLifeBar, this.updateTime);
    }
    start() {
        this._uiNodeControl.DisableBt('jump');
        this._uiNodeControl.DisableBt('speedUpWay');
        this._SkillsNode = this.heroBody.getChildByName("Skills");
        let target = this.node.getComponent(HeroTarget);
        target.statusNode = this._SkillsNode;
        target.lifeValueNode = this._followNode.getChildByName("lifeValue");
        target.RefresPool = this.HRefreshPool;
        target.StatusPool = this.HStatusPool;
    }

    onLastFrame() {
        if (!this._runState || !this._HeroHelper.isFootCollider)
            this.stopAnimationByName("run");
    }

    playAnimationByName(animName: string) {
        this._animations.play(animName);
    }

    stopAnimationByName(animName: string) {
        this._animations.stop(animName);
    }

    speedUp(): boolean {
        if (this._heroMamaget.isFreeze || this._heroMamaget.isDizziness)
            return false;
        let speed = this._heroMamaget.speedUpHero * this._faceTo;
        let time = this._heroMamaget.speedUpHeroTime;

        this._speedUpNode.zIndex = 1;
        this._speedUpNode.active = true;
        this._speedUpNode.parent = this.heroBody;
        this.playAnimationByName('speedUp');
        let heroCollider = this.heroBody.getComponent(HeroCollider);
        heroCollider.SpeedUp = speed;
        heroCollider.isSpeedUp = true;
        this.isSpeedUp = true;
        cc.tween(this._speedUpNode)
            .to(time / 2, { opacity: 200 })
            .call(() => {
                heroCollider.isSpeedUp = false;
                heroCollider.isSpeedDown = true;
            })
            .to(time / 2, { opacity: 0 })
            .call(() => {
                this._speedUpNode.active = false;
                if (this._runState && this._HeroHelper.isFootCollider)
                    this.playAnimationByName("run");
                else
                    this.playAnimationByName('speedUpEnd');
                heroCollider.isSpeedUp = false;
                heroCollider.isSpeedDown = false;
                this.isSpeedUp = false;
            })
            .start()
        return true;
    }

    jump() {
        if (this._heroMamaget.isFreeze || this._heroMamaget.isDizziness)
            return;
        if (this._isjumping > 0)
            this.jumpUp();
    }

    private jumpUp() {
        this._jumpState = 1;
        this.playAnimationByName("jumpUp");
        let lv = this._rigidBody.linearVelocity;
        if (this._isjumping == 1) {
            lv.y += this._heroMamaget.jumpSpeed / 2;
            lv.x += this._faceTo * 100;
        }
        else {
            lv.y += this._heroMamaget.jumpSpeed;
            lv.x += this._faceTo * 50;
        }
        this._rigidBody.linearVelocity = lv
        this._isjumping--;
    }

    private jumpEnd() {
        this._jumpState = 0;
        this.playAnimationByName("jumpDown");
    }
    BeginContact(event) {
        if (this.jumpState != 0)
            this.jumpEnd();
        if (this._runState) {
            this.playAnimationByName("run");
        }
        if (!this.isJumping)
            this._uiNodeControl.EnableBt('jump');
        let _tag = event.getUserData();
        if (_tag == TagWayBody2)
            this._uiNodeControl.EnableBt('speedUpWay');
        else if (_tag == TagAbyss) {
            this.walkStop();
            cc.Component.EventHandler.emitEvents(this.DieEvents, {
                target: this,
                masg: "掉入深渊"
            });
        }
        this._isjumping = 2;
        event.stopPropagation();
    }
    ChangeInContact(event) {
        if (this.PutNode) {
            let control = this._placeWay.getComponent(placeWayControl);
            control.setWay();
        }
    }
    EndContact(event) {
        if (!this.isJumping)
            this._uiNodeControl.DisableBt('jump');
        let _tag = event.getUserData();
        if (_tag == TagWayBody2)
            this._uiNodeControl.DisableBt('speedUpWay');
        event.stopPropagation();
    }
    walk() {
        if (this._heroMamaget.isFreeze || this._heroMamaget.isDizziness)
            return;
        if (this._faceTo == 1) {
            this.walkRight();
        }
        else if (this._faceTo == -1) {
            this.walkLeft()
        }
    }
    //技能施法
    skill() {
        if (this._heroMamaget.isFreeze || this._heroMamaget.isDizziness)
            return;
        if (!this._SkillsNodeControl) {
            this._SkillsNodeControl = this.skillContrl.getComponent(SkillsNodeControl);
        }
        if (!this.onSkillNode || !this._SkillsNodeControl._SkillControl) {//发射默认技能
            if (!this._defaultSkillLaunch) {
                this.onSkillNode = this._SkillsNodeControl.Skill();
                if (this.onSkillNode) {
                    this.onSkillCount = this._SkillsNodeControl.SkillCount();
                    let _skill = this.onSkillNode.getComponent(Skill);
                    this.setskill(this.onSkillNode)
                    this._defaultSkillLaunch = _skill._SkillLaunch;
                }
            }
            else {
                this._defaultSkillLaunch.doLaunch(this._faceTo);
            }
        }
        else {
            this.setskill(this.onSkillNode)
        }
    }
    private setskill(_onSkillNode: cc.Node) {
        _onSkillNode.group = this.skillStore.group;
        let put = _onSkillNode.getComponent(Skill);
        put.heroTargetBase = this.node.getComponent(TargetBase);
        put.init();
        if (put.attackType == MyEnums.attackType.hit) {
            put.activateSkill(this.heroBody.getChildByName("launch"), cc.v2(50, 10), this._faceTo, MyEnums.SkillSource.hero);
        }
        else if (put.attackType == MyEnums.attackType.self) {
            put.activateSkill(this.heroBody.getChildByName("launch"), cc.Vec2.ZERO, this._faceTo, MyEnums.SkillSource.hero);
        }
        this.onSkillCount--;
        this._SkillsNode.addChild(_onSkillNode);
        let checked = put.attackType == MyEnums.attackType.self;
        this.SkillBack(_onSkillNode.name, checked);
        this.skilled(checked);
    }
    private skilled(isSelf: boolean) {
        if (this.onSkillCount <= 0 || isSelf) {
            this.onSkillNode = null;
            this.onSkillCount = 0;
        }
        else {
            if (!this._SkillsNodeControl) {
                this._SkillsNodeControl = this.skillContrl.getComponent(SkillsNodeControl);
            }
            this.onSkillNode = this._SkillsNodeControl.Skill();
        }
    }
    //选中技能的回调
    onSkill(event) {
        if (event.SkillType != MyEnums.attackType.put) {
            this.onSkillNode = event.SkillNode;
            this.onSkillCount = event.SkillCount;
            this.onSkillId = event.SkillId;
            if (this.PutNode || this.isSetWaying) {
                let control = this._placeWay.getComponent(placeWayControl);
                control.clearItem();
                this.PutNode = null;
            }
            if (event.SkillType == MyEnums.attackType.self) {
                this.skill();
            }
        }
        else {
            this.PutNode = event.SkillNode;
            this.setPutSkill();
        }
    }
    //触发放置类技能释放
    setPutSkill() {
        this.isSetWaying = true;
        let control = this._placeWay.getComponent(placeWayControl);
        control.setWay();
    }
    //放置类技能选中位置后施法
    placeWaySelect(event) {
        this.isSetWaying = false;
        if (this.PutNode) {
            let wayNode = this.ObjectNode.getChildByUuid(this._HeroHelper.uuidWayCollider);
            let wayControl = wayNode.getComponent(WayBaseControl);
            let position: cc.Vec3 = event.position;
            position.y -= wayControl.offsetUp / 2;
            this.PutNode.group = this.skillStore.group;
            this.PutNode.zIndex = event.tag + 1;
            let put = this.PutNode.getComponent(Skill);
            put.heroTargetBase = this.node.getComponent(TargetBase);
            put.init();
            put.activateSkill(wayNode, cc.v2(position.x, position.y), this._faceTo);//SelfNode是炮台，position是炮台相对于wayNode的位置
            this.onSkillCount--;
            this._SkillsNode.addChild(this.PutNode);
            let checked = put.attackType == MyEnums.attackType.self;
            this.SkillBack(this.PutNode.name, checked);
            let control = this._placeWay.getComponent(placeWayControl);
            control.clearItem();
            if (put.SourceNode.name == "PutBody")
                wayControl.setPutOccupy(event.tag, put.SourceNode.uuid);

            if (this.onSkillCount <= 0) {
                this.PutNode = null;
            }
            else {
                if (!this._SkillsNodeControl) {
                    this._SkillsNodeControl = this.skillContrl.getComponent(SkillsNodeControl);
                }
                this.PutNode = this._SkillsNodeControl.Skill();
                this.onSkillCount = this._SkillsNodeControl.SkillCount();
            }
        }
    }
    //技能施法后的回调
    SkillBack(id: string, checked: boolean) {
        cc.Component.EventHandler.emitEvents(this.SkillBackEvents, {
            target: this,
            checked: checked,
            id: id
        });
    }

    walkStop() {
        this.runSpeed(0);
    }

    walkLeft() {
        if (this.isSpeedUp)
            return;
        let speed = this._heroMamaget.runSpeed;
        this.animLeft();
        this.runSpeed(speed * this._faceTo);
    }

    animLeft() {
        if (this._faceTo != -1) {
            this._faceTo = -1;
            if (this._faceTo != this.heroBody.scaleX)
                this.heroBody.scaleX = this._faceTo;
        }
        this.playAnimationByName("run");
    }

    walkRight() {
        if (this.isSpeedUp)
            return;
        let speed = this._heroMamaget.runSpeed;
        this.animRight();
        this.runSpeed(speed);
    }

    runSpeed(speed: number) {
        if (speed != 0) {
            this._runState = true;
            this._heroMamaget.SetRunState(true, this._faceTo);
        }
        else {
            this._runState = false;
            this._heroMamaget.SetRunState(false, this._faceTo);
        }
    }

    animRight() {
        if (this._faceTo != 1) {
            this._faceTo = 1;
            if (this._faceTo != this.heroBody.scaleX)
                this.heroBody.scaleX = this._faceTo;
        }
        this.playAnimationByName("run");
    }
    //设置血量并更新血条
    updateLifeBar() {
        if (this._heroMamaget.heroDie)
            return;
        if (this._lifeBarNode) {
            if (this._heroMamaget.life != this._heroMamaget.lifeMax) {
                this._lifeBarNode.active = true;
                this._progress.progress = this._heroMamaget.life / this._heroMamaget.lifeMax;
            }
            else {
                this._lifeBarNode.active = false;
            }
        }
        if (this._heroMamaget.life <= 0) {
            cc.Component.EventHandler.emitEvents(this.DieEvents, {
                target: this,
                masg: "失血过多"
            });
            this._heroMamaget.heroDie = true;
            return;
        }
        this._heroMamaget.updateLife(this.updateTime);
    }
    update(dt) {
        this._HeroHelper.SetWorldPosition(this.heroBody.convertToWorldSpaceAR(cc.v2(0, 0)));
        if (this._jumpState == 1) {
            var velocity = this._rigidBody.linearVelocity;
            if (velocity.y < 0)
                this._jumpState = -1;
        }
    }
}
